#ifndef BTN7919_H
#define BTN7919_H

/*
  Motor <- BTN7919 <- ESP32
           front
          /------\
  left   |        | right
           rear

 左电机 + 黑线 - 电机1 out1 线圈侧 - BTN7919 PMW1 - GPIO 32 黄色
 左电机 - 红线 - 电机1 out1 开关侧 - BTN7919 PMW2 - GPIO 33 绿色

 右电机 + 红线 - 电机2 out2 线圈侧 - BTN7919 PMW3 - GPIO 26 黄色
 右电机 - 黑线 - 电机2 out2 开关侧 - BTN7919 PMW4 - GPIO 27 绿色
*/

// Motor left
int motor_left_Pin_P = 32;  // 黄色 PMW1 motor black line
int motor_left_Pin_N = 33;  //  绿色 PMW2 motor red line

// Motor right
int motor_right_Pin_P = 26;  // 黄色  PMW3  motor red line
int motor_right_Pin_N = 27;  // 绿色 PMW4   motor black line

// Setting PWM properties
const int freq = 30000;
const int resolution = 8;

enum ROBOT_ACTION_CODE {
  ROBOT_FORWARD = 1,
  ROBOT_BACKWARD,
  ROBOT_STOP,
  // turn
  ROBOT_LEFT_FORWARD,
  ROBOT_RIGHT_FORWARD,
  ROBOT_LEFT_SPIN,
  ROBOT_RIGHT_SPIN,
  ROBOT_LEFT_STEP,
  ROBOT_RIGHT_STEP,
  // speed
  ROBOT_SPEED_UP,
  ROBOT_SPEED_DOWN,
  ROBOT_LEFT_SPEED_UP,
  ROBOT_LEFT_SPEED_DOWN,
  ROBOT_RIGHT_SPEED_UP,
  ROBOT_RIGHT_SPEED_DOWN
};
/*
// robot action code
const int ROBOT_FORWARD = 1;
const int ROBOT_BACKWARD = 2;
const int ROBOT_STOP = 5;
// turn
const int ROBOT_LEFT_FORWARD = 3;
const int ROBOT_RIGHT_FORWARD = 4;
const int ROBOT_LEFT_SPIN = 101;
const int ROBOT_RIGHT_SPIN = 102;
const int ROBOT_LEFT_STEP = 201;
const int ROBOT_RIGHT_STEP = 202;
// speed
const int ROBOT_SPEED_UP = 6;
const int ROBOT_SPEED_DOWN = 7;
const int ROBOT_LEFT_SPEED_UP = 13;
const int ROBOT_LEFT_SPEED_DOWN = 11;
const int ROBOT_RIGHT_SPEED_UP = 14;
const int ROBOT_RIGHT_SPEED_DOWN = 12;
*/
// car running state
enum ROBOT_ACTION_CODE car_state = ROBOT_STOP;

// PWM - speed
int left_speed = 200;
int right_speed = left_speed + 10;
const int speed_step = 10;

void car_forward() {
  ledcWrite(motor_left_Pin_P, left_speed);
  ledcWrite(motor_left_Pin_N, 0);
  // right
  ledcWrite(motor_right_Pin_P, right_speed);
  ledcWrite(motor_right_Pin_N, 0);
}

void car_back() {
  // left
  ledcWrite(motor_left_Pin_P, 0);
  ledcWrite(motor_left_Pin_N, left_speed);
  // right
  ledcWrite(motor_right_Pin_P, 0);
  ledcWrite(motor_right_Pin_N, right_speed);
}

void car_stop() {
  // Stop the DC motor
  ledcWrite(motor_left_Pin_P, 0);
  ledcWrite(motor_left_Pin_N, 0);
  // right
  ledcWrite(motor_right_Pin_P, 0);
  ledcWrite(motor_right_Pin_N, 0);
}

void car_turn_left() {
  // stop left motor
  ledcWrite(motor_left_Pin_P, 0);
  ledcWrite(motor_left_Pin_N, 0);
  // rotor right motor
  ledcWrite(motor_right_Pin_P, right_speed);
  ledcWrite(motor_right_Pin_N, 0);
}

void car_turn_right() {
  // rotor left motor
  ledcWrite(motor_left_Pin_P, left_speed);
  ledcWrite(motor_left_Pin_N, 0);
  // stop  right motor
  ledcWrite(motor_right_Pin_P, 0);
  ledcWrite(motor_right_Pin_N, 0);
}

void car_turn_left_step() {
  car_turn_left();
  delay(100);
  car_stop();
}

void car_turn_right_step() {
  car_turn_right();
  delay(100);
  car_stop();
}

void car_turn_left_spin() {
  // re-rotor left motor
  ledcWrite(motor_left_Pin_P, 0);
  ledcWrite(motor_left_Pin_N, left_speed);
  // rotor right motor
  ledcWrite(motor_right_Pin_P, right_speed);
  ledcWrite(motor_right_Pin_N, 0);
}

void car_turn_right_spin() {
  // rotor left motor
  ledcWrite(motor_left_Pin_P, left_speed);
  ledcWrite(motor_left_Pin_N, 0);
  // re-rotor  right motor
  ledcWrite(motor_right_Pin_P, 0);
  ledcWrite(motor_right_Pin_N, right_speed);
}

void running_with_new_speed() {
  switch (car_state) {
    case ROBOT_FORWARD:
      car_forward();
      break;
    case ROBOT_BACKWARD:
      car_back();
      break;
    case ROBOT_LEFT_FORWARD:
      car_turn_left();
      break;
    case ROBOT_RIGHT_FORWARD:
      car_turn_right();
      break;
    case ROBOT_LEFT_SPIN:
      car_turn_left_spin();
      break;
    case ROBOT_RIGHT_SPIN:
      car_turn_right_spin();
      break;
    default:
      break;
  }
}

void left_speed_up_value() {
  left_speed += speed_step;
  if (left_speed > 255) {
    left_speed = 255;
  }
}

void left_speed_down_value() {
  left_speed -= speed_step;
  if (left_speed < 0) {
    left_speed = 0;
  }
}

void right_speed_up_value() {
  right_speed += speed_step;
  if (right_speed > 255) {
    right_speed = 255;
  }
}

void right_speed_down_value() {
  right_speed -= speed_step;
  if (right_speed < 0) {
    right_speed = 0;
  }
}

void car_left_speed_up() {
  left_speed_up_value();
  running_with_new_speed();
}
void car_left_speed_down() {
  left_speed_down_value();
  running_with_new_speed();
}

void car_right_speed_up() {
  right_speed_up_value();
  running_with_new_speed();
}

void car_right_speed_down() {
  right_speed_down_value();
  running_with_new_speed();
}

void car_speed_up() {
  left_speed_up_value();
  right_speed_up_value();
  running_with_new_speed();
}

void car_speed_down() {
  left_speed_down_value();
  right_speed_down_value();
  running_with_new_speed();
}

void car_action(ROBOT_ACTION_CODE car_cmd) {
  switch (car_cmd) {
    case ROBOT_FORWARD:
      car_forward();
      car_state = ROBOT_FORWARD;
      break;
    case ROBOT_BACKWARD:
      car_back();
      car_state = ROBOT_BACKWARD;
      break;
    case ROBOT_STOP:
      car_stop();
      car_state = ROBOT_STOP;
      break;
    case ROBOT_LEFT_FORWARD:
      car_turn_left();
      car_state = ROBOT_LEFT_FORWARD;
      break;
    case ROBOT_RIGHT_FORWARD:
      car_turn_right();
      car_state = ROBOT_RIGHT_FORWARD;
      break;
    case ROBOT_LEFT_STEP:
      car_turn_left_step();
      car_state = ROBOT_STOP;
      break;
    case ROBOT_RIGHT_STEP:
      car_turn_right_step();
      car_state = ROBOT_STOP;
      break;
    case ROBOT_LEFT_SPIN:
      car_turn_left_spin();
      car_state = ROBOT_LEFT_SPIN;
      break;
    case ROBOT_RIGHT_SPIN:
      car_turn_right_spin();
      car_state = ROBOT_RIGHT_SPIN;
      break;
    case ROBOT_SPEED_UP:
      car_speed_up();
      break;
    case ROBOT_SPEED_DOWN:
      car_speed_down();
      break;
    case ROBOT_LEFT_SPEED_UP:
      car_left_speed_up();
      break;
    case ROBOT_LEFT_SPEED_DOWN:
      car_left_speed_down();
      break;
    case ROBOT_RIGHT_SPEED_UP:
      car_right_speed_up();
      break;
    case ROBOT_RIGHT_SPEED_DOWN:
      car_right_speed_down();
      break;
    default:
      break;
  }  // switch
};

void setup_btn7919() {
  // sets the pins as outputs:
  pinMode(motor_right_Pin_P, OUTPUT);
  pinMode(motor_right_Pin_N, OUTPUT);

  pinMode(motor_left_Pin_P, OUTPUT);
  pinMode(motor_left_Pin_N, OUTPUT);

  // configure LED PWM functionalitites
  // ledcAttach(motor_left_Pin_P, pwmChannel_motor_left_forward);
  // ledcAttach(motor_left_Pin_N, pwmChannel_motor_left_backward);
  ledcAttach(motor_left_Pin_P, freq, resolution);
  ledcAttach(motor_left_Pin_N, freq, resolution);

  ledcAttach(motor_right_Pin_P, freq, resolution);
  ledcAttach(motor_right_Pin_N, freq, resolution);

  //
  // ledcSetup(pwmChannel_motor_left_forward, freq, resolution);
  // ledcSetup(pwmChannel_motor_left_backward, freq, resolution);
  // right
  // ledcAttach(motor_right_Pin_P, pwmChannel_motor_right_forward);
  // ledcAttach(motor_right_Pin_N, pwmChannel_motor_right_backward);

  // ledcSetup(pwmChannel_motor_right_forward, freq, resolution);
  // ledcSetup(pwmChannel_motor_right_backward, freq, resolution);
}

void loop_btn7919() {
}

#endif /* BTN7919_H */